<?php

namespace Gql\Core;

use ReflectionClass;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use ReflectionParameter;

trait DependencyTrait
{


    public function resolveClassMethodDependencies($parameters = [], $instance, $method)
    {
        if (!method_exists($instance, $method)) {
            return $parameters;
        }

        return $this->resolveMethodDependencies(
            $parameters, new ReflectionMethod($instance, $method)
        );
    }


    public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
    {
        $instanceCount = 0;

        $values = array_values($parameters);

        foreach ($reflector->getParameters() as $key => $parameter) {
            $instance = $this->transformDependency(
                $parameter, $parameters
            );
            if (!is_null($instance)) {
                $instanceCount++;

                $this->spliceIntoParameters($parameters, $key, $instance);
            } elseif (!isset($values[$key - $instanceCount]) &&
                $parameter->isDefaultValueAvailable()) {
                $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue());
            }
        }
        return $parameters;
    }


    protected function transformDependency(ReflectionParameter $parameter, array &$parameters)
    {
        $class = $parameter->getClass();

        if ($class) {
            $param = $this->getParameter($class->name, $parameters);
            if ($param) {
                return $param;
            }
            return $parameter->isDefaultValueAvailable()
                ? $parameter->getDefaultValue()
                : $this->container->make($class->name);
        }
    }

    public function getClassInstance(string $className, ReflectionClass $class = null)
    {
        if (!$this->container->has($className) && !is_null($class)) {
            $this->container->singleton($className, $class);
        }
    }

    public function getParameter($class, array &$parameters)
    {
        $index = -1;
        foreach ($parameters as $key => $parameter) {
            if ($parameter instanceof $class) {
                $index = $key;
                continue;
            }
        }
        if ($index > -1) {
            return array_splice($parameters, $index, 1)[0];
        }
    }

    /**
     * Splice the given value into the parameter list.
     *
     * @param  array $parameters
     * @param  string $offset
     * @param  mixed $value
     * @return void
     */
    protected function spliceIntoParameters(array &$parameters, $offset, $value)
    {
        array_splice(
            $parameters, $offset, 0, [$value]
        );
    }
}
